package main

import (
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

const FileRoot = "./doc/21_channel"
const FileSuffix = "txt"

var (
	chanNum           = 100
	writeFinishChan   = make(chan bool, 1)
	writeFileNameChan = make(chan string, chanNum)
	sortFinishChan    = make(chan bool, 1)
	sortFileNameChan  = make(chan string, chanNum)
)

func main() {
	for i := 0; i < chanNum; i++ {
		go writeDataToFile(i + 1)
	}
	<-writeFinishChan
	for i := 0; i < chanNum; i++ {
		go sortData()
	}
	<-sortFinishChan
}

func writeDataToFile(fileIndex int) {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	fileName := fmt.Sprintf("randInt_%v", fileIndex)
	filePath := fmt.Sprintf("%s/%s.%s", FileRoot, fileName, FileSuffix)
	defer writeInFinishChan(fileName, writeFileNameChan, writeFinishChan)
	nums := make([]int, 0)
	for i := 0; i < 1000; i++ {
		nums = append(nums, r.Int())
	}
	err := writeIntSliceInFile(filePath, nums)
	if err != nil {
		fmt.Printf("write data to file %v err: %v", fileIndex, err)
		return
	}
}

func sortData() {
	writeFileName := <-writeFileNameChan
	writeFilePath := fmt.Sprintf("%s/%s.%s", FileRoot, writeFileName, FileSuffix)
	sortFileName := fmt.Sprintf("%s_sorted", writeFileName)
	sortFilePath := fmt.Sprintf("%s/%s.%s", FileRoot, sortFileName, FileSuffix)
	defer writeInFinishChan(sortFileName, sortFileNameChan, sortFinishChan)
	writeFile, err := os.OpenFile(writeFilePath, os.O_RDONLY, 0777)
	if err != nil {
		fmt.Printf("sort data err: %v", err)
		return
	}
	defer writeFile.Close()
	reader := bufio.NewReader(writeFile)
	nums := make([]int, 0)
	for {
		str, err := reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			fmt.Printf("sort data err: %v", err)
			return
		}
		str, _ = strings.CutSuffix(str, "\n")
		intData, err := strconv.Atoi(str)
		if err != nil {
			fmt.Printf("sort data err: %v, %v", str, err)
			return
		}
		nums = append(nums, intData)
	}
	sort.Ints(nums)
	err = writeIntSliceInFile(sortFilePath, nums)
	if err != nil {
		fmt.Printf("sort data err: %v", err)
		return
	}
}

func writeInFinishChan(checkChanItem string, checkChan chan string, finishChan chan bool) {
	checkChan <- checkChanItem
	if len(checkChan) >= chanNum {
		close(checkChan)
		finishChan <- true
		close(finishChan)
	}
}

func writeIntSliceInFile(filePath string, nums []int) error {
	file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0777)
	if err != nil {
		return err
	}
	defer file.Close()
	writer := bufio.NewWriter(file)
	for _, v := range nums {
		writer.WriteString(fmt.Sprintf("%v\n", v))
	}
	writer.Flush()
	return nil
}
